﻿using System;
using System.Collections.Generic;
using Xunit;

namespace Lr.Core.Tests._extensions_
{
    public class DateTimeExtensionsTests
    {
        #region IsDay Method Family
        [Fact]
        public void IsDay_Returns_True_On_Correct_DayOfWeek()
        {
            // Arrange
            var expected = true;
            var input = new DateTime(2014, 06, 16, 18, 09, 35);

            // Act
            var actual = input.IsDay(DayOfWeek.Monday);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void IsDay_Returns_False_On_Incorrect_DayOfWeek()
        {
            // Arrange
            var expected = false;
            var input = new DateTime(2014, 06, 16, 18, 09, 35);

            // Act
            var actual = input.IsDay(DayOfWeek.Tuesday);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void IsWeekend_Returns_True_On_WeekendDays()
        {
            // Arrange
            var expected = true;
            var input = new List<DateTime>() {
                new DateTime(2014, 06, 14),
                new DateTime(2014, 06, 15)
            };

            // Act
            foreach (var date in input) {
                var actual = date.IsWeekend();

                // Assert
                Assert.Equal(expected, actual);
            }
        }

        [Fact]
        public void IsWeekend_Returns_False_On_WeekDays()
        {
            // Arrange
            var expected = false;
            var input = new List<DateTime>() {
                new DateTime(2014, 06, 16),
                new DateTime(2014, 06, 17),
                new DateTime(2014, 06, 18),
                new DateTime(2014, 06, 19),
                new DateTime(2014, 06, 20)
            };

            // Act
            foreach (var date in input) {
                var actual = date.IsWeekend();

                // Assert
                Assert.Equal(expected, actual);
            }
        }

        [Fact]
        public void IsXxxDay_Returns_True_On_XxxDay()
        {
            // Arrange            
            var expected = true;

            // Act
            // Assert
            Assert.Equal(expected, new DateTime(2014, 06, 16).IsMonday());
            Assert.Equal(expected, new DateTime(2014, 06, 17).IsTuesday());
            Assert.Equal(expected, new DateTime(2014, 06, 18).IsWednesday());
            Assert.Equal(expected, new DateTime(2014, 06, 19).IsThursday());
            Assert.Equal(expected, new DateTime(2014, 06, 20).IsFriday());
            Assert.Equal(expected, new DateTime(2014, 06, 21).IsSaturday());
            Assert.Equal(expected, new DateTime(2014, 06, 22).IsSunday());
        }

        [Fact]
        public void IsXxxDay_Returns_True_On_YyyDay()
        {
            // Arrange            
            var expected = false;

            // Act
            // Assert
            Assert.Equal(expected, new DateTime(2014, 06, 15).IsMonday());
            Assert.Equal(expected, new DateTime(2014, 06, 16).IsTuesday());
            Assert.Equal(expected, new DateTime(2014, 06, 17).IsWednesday());
            Assert.Equal(expected, new DateTime(2014, 06, 18).IsThursday());
            Assert.Equal(expected, new DateTime(2014, 06, 29).IsFriday());
            Assert.Equal(expected, new DateTime(2014, 06, 20).IsSaturday());
            Assert.Equal(expected, new DateTime(2014, 06, 21).IsSunday());
        }

        [Fact]
        public void IsDayIn_Returns_True_On_Correct_DaysOfWeek()
        {
            // Arrange
            var expected = true;
            var input = new DateTime(2014, 06, 16, 18, 09, 35);
            var days = new List<DayOfWeek>() { 
                DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Friday
            };

            // Act
            var actual = input.IsDayIn(days);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void IsDayIn_Returns_False_On_Incorrect_DaysOfWeek()
        {
            // Arrange
            var expected = false;
            var input = new DateTime(2014, 06, 16, 18, 09, 35);
            var days = new List<DayOfWeek>() { 
                DayOfWeek.Friday, DayOfWeek.Saturday, DayOfWeek.Sunday
            };

            // Act
            var actual = input.IsDayIn(days);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void IsDayIn_Returns_False_On_Null_DaysOfWeek()
        {
            // Arrange
            var expected = false;
            var input = new DateTime(2014, 06, 16, 18, 09, 35);
            List<DayOfWeek> days = null;

            // Act
            var actual = input.IsDayIn(days);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void IsDayIn_Returns_False_On_Empty_DaysOfWeek()
        {
            // Arrange
            var expected = false;
            var input = new DateTime(2014, 06, 16, 18, 09, 35);
            var days = new List<DayOfWeek>();

            // Act
            var actual = input.IsDayIn(days);

            // Assert
            Assert.Equal(expected, actual);
        }
        #endregion

        #region "NextDay Method Family"
        [Fact]
        public void NextDay_Returns_Correct_NextDay()
        {
            // Arrange
            var date = new DateTime(2014, 6, 17, 10, 28, 30);
            var expected = new DateTime(2014, 6, 18, 10, 28, 30);

            // Act            
            var actual = date.NextDay();

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void PreviousDay_Returns_Correct_PreviousDay()
        {
            // Arrange
            var date = new DateTime(2014, 6, 17, 10, 28, 30);
            var expected = new DateTime(2014, 6, 16, 10, 28, 30);

            // Act            
            var actual = date.PreviousDay();

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void NextDay_DayOfWeek_Returns_Correct_NextDay()
        {
            // Arrange
            var date = new DateTime(2014, 6, 17, 10, 28, 30);
            var expected = new DateTime(2014, 6, 20, 10, 28, 30);

            // Act            
            var actual = date.NextDay(DayOfWeek.Friday);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void NextDay_DayOfWeek_Returns_Correct_NextDay_7DaysForward()
        {
            // Arrange
            var date = new DateTime(2014, 6, 17, 10, 28, 30);
            var expected = new DateTime(2014, 6, 24, 10, 28, 30);

            // Act            
            var actual = date.NextDay(DayOfWeek.Tuesday);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void PreviousDay_DayOfWeek_Returns_Correct_PreviousDay()
        {
            // Arrange
            var date = new DateTime(2014, 6, 17, 10, 28, 30);
            var expected = new DateTime(2014, 6, 11, 10, 28, 30);

            // Act            
            var actual = date.PreviousDay(DayOfWeek.Wednesday);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void PreviousDay_DayOfWeek_Returns_Correct_PreviousDay_7DaysAgo()
        {
            // Arrange
            var date = new DateTime(2014, 6, 17, 10, 28, 30);
            var expected = new DateTime(2014, 6, 10, 10, 28, 30);

            // Act            
            var actual = date.PreviousDay(DayOfWeek.Tuesday);

            // Assert
            Assert.Equal(expected, actual);
        }

        [Fact]
        public void NextDay_DayOfWeek_Bulk_Test()
        {
            // Arrange
            var date = new DateTime(2014, 6, 15, 10, 58, 44); // starting on sunday

            for (int i = 1; i <= 7; i++) {
                // Act
                var expected = date.AddDays(i);
                var actual = date.PreviousDay((DayOfWeek)i);

                // Assert
                DateTime.Equals(expected, actual);
            }
        }

        [Fact]
        public void PreviousDay_DayOfWeek_Bulk_Test()
        {
            // Arrange
            var date = new DateTime(2014, 6, 15, 10, 58, 44); // starting on sunday
            
            for (int i = 1; i <= 7; i++) {
                // Act
                var expected = date.AddDays(i * -1);
                var actual = date.PreviousDay((DayOfWeek)i);

                // Assert
                DateTime.Equals(expected, actual);
            }
        }
        #endregion
    }
}
